package cn.sinjet.model.mcuupgrade;

import java.io.File;
import java.io.FileInputStream;
import java.math.BigInteger;
import java.security.MessageDigest;

import android.os.Environment;
import android.util.Log;
import cn.sinjet.communication.bluetooth.BluetoothModel;
import cn.sinjet.model.carassist.AppModel;
import cn.sinjet.model.carsystem.CarModel;
import com.mgroup.wazehelper.R;
import cn.sinjet.viewmodel.ViewModel;
import cn.sinjet.utils.ShowDialogUtil;
import cn.sinjet.utils.ShowDialogUtil.OnDialogAction;

public class McuUpgradeModelSimple implements DownloadStatusCallBack {
	private static McuUpgradeModelSimple upgradeModelSimple = null;
	public synchronized static McuUpgradeModelSimple getInstance(){
		if(upgradeModelSimple == null)
			upgradeModelSimple = new McuUpgradeModelSimple();
		return upgradeModelSimple;
	}

	String magicStringMCUString = null;
	
	byte[] pakData = null;
	String pakMD5 = null;
	String pakMagicString = null;
	
	int versionMCU = 0;
	int versionFile = 0;
	int versionService = 0;
	
	int readyForUpgradeVersion = 0;

	private String strUpdateContent;

	private String genFileNameByMagicString(String magicString)
	{
		return String.format("mcu_%s.pak", magicString);
	}

	private String genreqFlagByMagicString(String magicString)
	{
		return String.format("mcu_%s", magicString);
	}
	
	public void checkUpgradeFile(String magicString) {
		MCUFetchHex MCUFetchUpgradeFileInfo = new MCUFetchHex();
		MCUFetchUpgradeFileInfo.checkNewFile(McuUpgradeModelSimple.this,
				null,
				genreqFlagByMagicString(magicString),genFileNameByMagicString(magicString),
				true,versionMCU);
	}

	String strMCUVersionDisplay = null;
	private void showMCUVersion(boolean bUpdating,int dataOffset)
	{
		StringBuilder stringMCUVersion;
		stringMCUVersion = new StringBuilder("  固件版本: ");
		if (versionMCU > 0)
		{
			stringMCUVersion.append(String.format("%d",versionMCU));
		}
		if (bUpdating && pakData != null && pakData.length > 0)
		{
			stringMCUVersion.append("\r\n");
			stringMCUVersion.append(String.format("  %.3f@%.1fM"
					,100.0*dataOffset/pakData.length
					,pakData.length/4096.0/4096.0));		
		}
		if (readyForUpgradeVersion > 0) {
			stringMCUVersion.append(String.format("\r\n  已准备好更新到：%d，点击更新。", readyForUpgradeVersion));
		}
		if (strMCUVersionDisplay == null || !strMCUVersionDisplay.equals(stringMCUVersion.toString())) {
			ViewModel.getIns().setViewProperty(R.id.mcu_version, stringMCUVersion.toString());
			ViewModel.getIns().refreshView(R.id.mcu_version);							
		}
	}
	
	boolean haveFetchMCUFile = false;
	public void readAndFetchMCUUpgradeFile(boolean bForceRead,boolean bReadFromService)
	{
		if (magicStringMCUString == null)
		{
			return;
		}
		if (versionMCU == 0)
		{
			return;
		}
		
		if (bForceRead || pakData == null)
		{
			try {
				File file = new File(Environment.getExternalStorageDirectory(),genFileNameByMagicString(magicStringMCUString));
				if (file.isFile())
				{
					FileInputStream fin = new FileInputStream(file);		
					int length = fin.available();
					if (length > 0)
					{
						byte[] pakDataSrc = new byte[length];
						fin.read(pakDataSrc);
						pakData = pakDataSrc;
						pakMagicString = magicStringMCUString;
						versionFile = MCUUpgradeCommonFunction.getUnsignedByte(pakData[8])
							+ (MCUUpgradeCommonFunction.getUnsignedByte(pakData[9]) << 8)
							+ (MCUUpgradeCommonFunction.getUnsignedByte(pakData[10]) << 16)
							+ (MCUUpgradeCommonFunction.getUnsignedByte(pakData[11]) << 24);
						
						MessageDigest digest = MessageDigest.getInstance("MD5");
						digest.update(pakData);
						BigInteger bigInt = new BigInteger(1, digest.digest());
						pakMD5 = bigInt.toString(16);
						sendFileMD5(pakMD5);
					}	
					fin.close();
				}
			}
			catch (Exception ex) {
				ex.printStackTrace();
			}
		}

		if (bReadFromService)
		{
			if (!haveFetchMCUFile)
			{
				haveFetchMCUFile = true;
				checkUpgradeFile(magicStringMCUString);
				
			}
		}
	}

	private void recMCUMagicString(String magicString)
	{
		if (magicStringMCUString == null || !magicStringMCUString.equals(magicString))
		{
			magicStringMCUString = magicString;
			AppModel.getInstance().setModuleCode(magicStringMCUString);
			readAndFetchMCUUpgradeFile(false,true);
		}
	}

	private void recMCUVersion(int version)
	{
		if (versionMCU != version)
		{
			versionMCU = version;
			readAndFetchMCUUpgradeFile(false,true);
			showMCUVersion(false,0);
			if (versionMCU > 0 && versionMCU != 0xFFFFFFFF)
			{
				AppModel.getInstance().setModuleVersion(versionMCU);
			}
		}
	}

	private void packAndMsg(byte[] message,int len) {
		byte[] szMsg = new byte[len + 5];
		szMsg[0] = (byte) 0xFF;
		szMsg[1] = (byte) 0x55;
		szMsg[2] = (byte) (len + 1);
		szMsg[3] = (byte) 0x3A;
		System.arraycopy(message, 0, szMsg, 4, len);
		
		byte sum = 0;
		int s = 0;
		int i = 0;
		for (i = 2; i < len + 4; i++) {
			s += (szMsg[i] & 0xFF);
		}
		sum = (byte) (s & 0xFF);
		szMsg[len + 4] = sum;
		BluetoothModel.getInstance().sendMessage(szMsg);
		
		final StringBuilder stringBuilder = new StringBuilder(len);
		for (byte byteChar : message)
			stringBuilder.append(String.format("%02X ", byteChar));
		Log.d("mcu_upgrade","onSend: "+ stringBuilder.toString());
	}

	private void reqMCUMagicString() {
		byte[] buf = new byte[2];
		buf[0] = 0x10;
		buf[1] = 0x00;
		packAndMsg(buf,buf.length);
	}

	private void reqMCUVersion(){
		byte[] buf = new byte[1];
		buf[0] = 0x12;
		packAndMsg(buf,buf.length);
	}

	private void reqMCUUUID(){
		byte[] buf = new byte[1];
		buf[0] = 0x14;
		packAndMsg(buf,buf.length);
	}

	private void sendFileMD5(String md5){
		if (md5 == null)
		{
			return;
		}
		
		byte[] buf = new byte[1+32];
		buf[0] = 0x16;
		for (int i = 0;i < 32;i++)
		{
			buf[1+i] = (byte) md5.charAt(i);
		}
		packAndMsg(buf,buf.length);
	}
	
	private boolean sendPakData(int dataOffset,int dataLength) {
		if (pakData == null)
		{
			return false;
		}
		if (!magicStringMCUString.equals(pakMagicString))
		{
			return false;
		}
		if (dataOffset + dataLength > pakData.length)
		{
			dataLength = pakData.length - dataOffset;
		}
		if (dataLength <= 0)
		{
			return false;
		}
		if (dataLength > 200)
		{
			dataLength = 200;
		}
		
		byte[] buf = new byte[1+4+200];
		buf[0] = 0x20;
		buf[1] = (byte)(dataOffset & 0xff);
		buf[2] = (byte)((dataOffset >> 8) & 0xff);
		buf[3] = (byte)((dataOffset >> 16) & 0xff);
		buf[4] = (byte)((dataOffset >> 24) & 0xff);
		
		for (int i = 0;i < dataLength;i++)
		{
			if (dataOffset+i < pakData.length)
			{
				buf[5+i] = pakData[dataOffset+i];
			}
			else
			{
				buf[5+i] = (byte)0x0ff;
			}
		}
		packAndMsg(buf,1+4+dataLength);	
		return true;
	}

	private void reqMCUStartUpgrade(){
		byte[] buf = new byte[2];
		buf[0] = 0x30;
		buf[1] = 0x01;
		packAndMsg(buf,buf.length);
	}

	public void checkVersion()
	{
		if (magicStringMCUString == null)
		{
			reqMCUMagicString();
		}
		else if (0 == versionMCU)
		{
			reqMCUVersion();
		}
		else if (versionMCU != 0xFFFFFFFF)
		{
			if (CarModel.getInstance().devModule.getMcuUUID() == null)
			{
				reqMCUUUID();
			}
		}
	}
	
	private boolean needReloadFile = false;
	public int onRecvUpgradeMsg(byte[] message){//the message is packed
		final StringBuilder stringBuilder = new StringBuilder(message.length);
		for (byte byteChar : message)
			stringBuilder.append(String.format("%02X ", byteChar));
		Log.d("mcu_upgrade_simple","onReceived: "+ stringBuilder.toString());
		
		if (needReloadFile)
		{
			needReloadFile = false;
			readAndFetchMCUUpgradeFile(true,false);
		}
		if (0x3A == message[0])
		{
			switch (message[1])
			{
			case 0x11:
			{
				byte[] byteArray = new byte[8];
				System.arraycopy(message, 2, byteArray, 0, 8);
				String str = new String(byteArray);
				recMCUMagicString(str);				
			}
				break;
			case 0x13:
			{
				byte[] byteArray = new byte[8];
				System.arraycopy(message, 2, byteArray, 0, 8);
				recMCUVersion(MCUUpgradeCommonFunction.transVersionToInt(byteArray));
			}
				break;
			case 0x15:
			{
				StringBuilder strMCUUUIDBuilder;
				strMCUUUIDBuilder = new StringBuilder();
				for (int i = 2;i < message.length;i++)
				{
					strMCUUUIDBuilder.append(String.format("%02x", message[i]));
				}
				CarModel.getInstance().devModule.setMcuUUID(strMCUUUIDBuilder.toString());
			}
				break;
			case 0x17:
				sendFileMD5(pakMD5);
				break;
			case 0x21:
			{
				byte[] byteArray = new byte[8];
				System.arraycopy(message, 2, byteArray, 0, 8);
				String str = new String(byteArray);
				recMCUMagicString(str);				

				int dataOffset = MCUUpgradeCommonFunction.getUnsignedByte(message[2+8])
						+ (MCUUpgradeCommonFunction.getUnsignedByte(message[3+8]) << 8)
						+ (MCUUpgradeCommonFunction.getUnsignedByte(message[4+8]) << 16)
						+ (MCUUpgradeCommonFunction.getUnsignedByte(message[5+8]) << 24);
				int dataLength = MCUUpgradeCommonFunction.getUnsignedByte(message[6+8])
						+ (MCUUpgradeCommonFunction.getUnsignedByte(message[7+8]) << 8);
				
				if (sendPakData(dataOffset,dataLength))
				{
					readyForUpgradeVersion = 0;
					showMCUVersion(true,dataOffset);
				}
			}
				break;
			case 0x31:
			{
				if (0x01 == message[2])
				{
					readyForUpgradeVersion = MCUUpgradeCommonFunction.getUnsignedByte(message[3])
							+ (MCUUpgradeCommonFunction.getUnsignedByte(message[4]) << 8)
							+ (MCUUpgradeCommonFunction.getUnsignedByte(message[5]) << 16)
							+ (MCUUpgradeCommonFunction.getUnsignedByte(message[6]) << 24);
					showMCUVersion(false,0);
				}
			}
				break;
			default:
				break;
			}
		}

		checkVersion();

		return 0;
	}

	private void showUUIDDialog(String content){
		Log.d("dialog", "showUUIDDialog");
		ShowDialogUtil dialogUtil = new ShowDialogUtil();
		dialogUtil.setButtonText("确定", "取消");
		dialogUtil.setOnDialogActionListern(new OnDialogAction() {
			
			@Override
			public void onPositive() {
				// TODO Auto-generated method stub
				Log.d("dialog", "onPositive");
			}
			
			@Override
			public void onNegative() {
				// TODO Auto-generated method stub
				Log.d("dialog", "onNegative");
			}
		});
		dialogUtil.showDialog("模块UUID", content);
	}

	public void showMCUUpgradeStartAsk(){
		ShowDialogUtil dialogUtil = new ShowDialogUtil();
		dialogUtil.setButtonText("更新", "不要");
		dialogUtil.setOnDialogActionListern(new OnDialogAction() {
			
			@Override
			public void onPositive() {
				// TODO Auto-generated method stub
				Log.d("dialog", "onPositive");
				reqMCUStartUpgrade();
			}
			
			@Override
			public void onNegative() {
				// TODO Auto-generated method stub
				Log.d("dialog", "onNegative");
			}
		});
		StringBuilder strBuilder = new StringBuilder();
		strBuilder.append("更新内容：");
		strBuilder.append("\r\n");
		strBuilder.append(strUpdateContent);
		strBuilder.append("\r\n");
		strBuilder.append("是否更新？");
		dialogUtil.showDialog("已准备好新的固件", strBuilder.toString());
	}

	int clickCount = 0;
	public void startUpgrade() {
		if (readyForUpgradeVersion > 0) {
			readyForUpgradeVersion = 0;
			showMCUVersion(false,0);
			showMCUUpgradeStartAsk();
		}

		clickCount++;
		if (clickCount >= 10)
		{
			clickCount = 0;
			if (CarModel.getInstance().devModule.getMcuUUID() != null)
			{
				showUUIDDialog(CarModel.getInstance().devModule.getMcuUUID());
			}
		}		
	}

	@Override
	public void downloadUpdateContent(String fileName, String strContent, int version) {
		// TODO Auto-generated method stub
		strUpdateContent = strContent;
		versionService = version;		
	}

	@Override
	public void downloadServiceFileInfo(String fileName, String fileMD5, String fileUrl, int length) {
		// TODO Auto-generated method stub
		//showMCUUpgradeFileDownloadAskTips(fileName,fileMD5,fileUrl,length);
		MCUFetchHex MCUFetchUpgradeFileInfo = new MCUFetchHex();
		MCUFetchUpgradeFileInfo.downloadFile(McuUpgradeModelSimple.this,fileMD5,fileUrl,fileName);
	}

	@Override
	public void downloadLocalIsNew(String fileName) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void downloadReloadFile(String fileName) {
		// TODO Auto-generated method stub
		needReloadFile = true;
	}

	public void showMCUUpgradeFileDownloadAskTips(final String fileName, final String fileMD5, final String fileUrl, final int length) {
		Log.d("dialog", "showMCUUpgradeFileDownloadAskTips");
		ShowDialogUtil dialogUtil = new ShowDialogUtil();
		dialogUtil.setButtonText("马上下载", "下次吧");
		dialogUtil.setOnDialogActionListern(new OnDialogAction() {
			
			@Override
			public void onPositive() {
				// TODO Auto-generated method stub
				Log.d("dialog", "onPositive");
				MCUFetchHex MCUFetchUpgradeFileInfo = new MCUFetchHex();
				MCUFetchUpgradeFileInfo.downloadFile(McuUpgradeModelSimple.this,fileMD5,fileUrl,fileName);
			}
			
			@Override
			public void onNegative() {
				// TODO Auto-generated method stub
				Log.d("dialog", "onNegative");
			}
		});
		StringBuilder strBuilder = new StringBuilder();
		strBuilder.append("更新内容：");
		strBuilder.append("\r\n");
		strBuilder.append(strUpdateContent);
		strBuilder.append("\r\n");
		strBuilder.append("文件大小：");
		strBuilder.append("\r\n");
		strBuilder.append(String.format("%.1fMB", length/1024.0/1024.0));
		dialogUtil.showDialog("有新的固件哦，是否下载", strBuilder.toString());
	}
}
